﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using BasketballAI.Infrastructure.Entity;
using System.Collections;
using Algorithms;
using DecTrees;

namespace BasketballAI.Infrastructure.GameItems
{
    public class Player:IItem
    {
        public delegate void delegateTrace(string traceTxt);
        #region Members
        public delegateTrace trace;
        //private static Global.Game Global.Game;            
        private String playerName;
        private bool hasBall;
        private Global.RoleOnCourt role;
        private int playerTeamIndex;
        private Global.PartOfcourt myHalfCort;
        //private Global.MovementDirections direction;
        private decitionTree offenceDecitionTree=null;
        private decitionTree defenceDecitionTree=null;
        List<PathFinderNode> destinationPath = null;
        Bitmap image;
        private Boolean GuardHadBall = false;
        private Point InitialGuardingPoint;
        private Boolean TakeBallFromBasket = false;
        private sbyte[,] direction = new sbyte[8, 2] { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 }, { -1, -1 } };
        
                            
        #endregion

        #region Constructors

        public Player()
        {
        }

        public Player(Point p_position, String p_name, Global.AstarPosition p_aStarPosition,int p_teamIndex,Bitmap p_bm,Global.RoleOnCourt p_role)
        {
            this.HasBall = false;
            this.PositionOnCourt = p_position;
            this.InitialGuardingPoint = p_position;
            this.playerName = p_name;
            this.AStarPosition = p_aStarPosition;
            this.playerTeamIndex = p_teamIndex;
            this.image = p_bm;
            this.role = p_role;
            if (p_teamIndex == 0)
                this.myHalfCort = Global.PartOfcourt.Right;
            else if (p_teamIndex == 1)
                this.myHalfCort = Global.PartOfcourt.Left;
            this.BuildOffenceDecisionTree();
            this.BuildDefenceDecisionTree();

            
        }   

        #endregion

        #region Properties
        
        public String PlayerName
        {
            get { return playerName; }
            set { playerName = value; }
        }        
        public bool HasBall
        {
            get { return hasBall; }
            set
            {
                hasBall = value;
                if (hasBall)
                {
                    if (this.playerTeamIndex == 0)//Right team
                        this.image = Properties.Resources.greenTeam_With_Ball;
                    else//Left team
                        this.image = Properties.Resources.red_Team_With_Ball;
                    Global.Game.Teams[this.playerTeamIndex].TeamStatus = Global.TeamStatus.Offence;
                    //Delete destination for ball.
                    Global.Game.Ball.DestinationOnCourtPix =Global.Game.ConvertPositionFromMat2Pix(Global.Game.Ball.PositionOnCourt);
                }
                else
                {
                    if (this.playerTeamIndex == 0)//Right team
                        this.image = Properties.Resources.greenTeam;
                    else
                        this.image = Properties.Resources.redTeam;
                }
            }
        }
     
        public List<PathFinderNode> DestinationPath
        {
            get { return destinationPath; }
            set { destinationPath = value;
                   if(destinationPath!=null)
                   {
                       if(this.destinationPath[0].X==this.PositionOnCourt.X&&this.destinationPath[0].Y==this.PositionOnCourt.Y)
                       {
                           //Remove same location.
                           this.destinationPath.Remove(this.destinationPath[0]); 
                       }
                   };
            }
        }

        public Bitmap Image
        {
            get { return image; }
            set { image = value; }
        }

        public Player GuardOnPlayer;

        #endregion
     

        #region Methods

        #region Player Moves
        /// <summary>
        /// Player goes by destination.
        /// </summary>
        private void Move()
        {
            
            
            if (this.DestinationPath != null && this.DestinationPath.Count > 0)
            {
                this.PositionOnCourt = new Point(this.DestinationPath[0].X, this.DestinationPath[0].Y);
                this.DestinationPath.Remove(this.DestinationPath[0]);
                if (this.hasBall)
                    Global.Game.Ball.PositionOnCourtPix = Global.Game.ConvertPositionFromMat2Pix(this.PositionOnCourt);
                trace(this.PlayerName + " function - Move");
            }
         
         
        }

        #endregion

        #region  Offence Player Questions

        /// <summary>
        /// Is the player holding the ball
        /// </summary>
        /// <returns>True if Player has ball , False if not</returns>
        public Boolean DoIhaveTheBall()
        {
             return hasBall;
           
        }

        /// <summary>
        /// Checks the distance between the player and the basket, If the distance is smaller than pre define shooting
        /// range radius - the player is at shooting range
        /// </summary>
        /// <returns>True if the player at shooting range, false otherwize</returns>
        public Boolean AmIinShootingRange()
        {
            int RangeFromBasket;
            Point BasketPoint;
            if (AmIinTeam(Global.Game.Teams[0]))  //finding which basket 
            {
                BasketPoint = new Point(Global.Game.Teams[0].TargetBasket.PositionOnCourt.X, Global.Game.Teams[0].TargetBasket.PositionOnCourt.Y);
            }
            else
            {
                BasketPoint = new Point(Global.Game.Teams[1].TargetBasket.PositionOnCourt.X, Global.Game.Teams[1].TargetBasket.PositionOnCourt.Y);
            }
            // Calculates range from basket
            RangeFromBasket =
                   (int)Math.Sqrt(
                   Math.Abs(PositionOnCourt.X - BasketPoint.X) *
                        Math.Abs(PositionOnCourt.X - BasketPoint.X)
                   +
                   (
                   Math.Abs(PositionOnCourt.Y - BasketPoint.Y) *
                        Math.Abs(PositionOnCourt.Y - BasketPoint.Y)
                   )
                   );

            if ((RangeFromBasket) < (Global.Game.ShootingRangeRadius))
            {
                return true;
            }
            else
            {
                return false;
            }

        }

        /// <summary>
            /// Check if there is a stright line between the player and Basket with no other player disturbing.
            /// </summary>
            /// <returns>True is there is such line, False if not</returns>
        public Boolean IsStrightLineToBasket()
        {
            if (AmIinTeam(Global.Game.Teams[0]))  //finding out which basket
            {
                return hasClearPathBetweenPoints(PositionOnCourt, Global.Game.Teams[0].TargetBasket.PositionOnCourt);
            }
            else
            {
                return hasClearPathBetweenPoints(PositionOnCourt, Global.Game.Teams[1].TargetBasket.PositionOnCourt);
            }
        }

        /// <summary>
        /// Check if there is a stright line between the player and one of the player in his team with no one in the middle.
        /// </summary>
        /// <returns>True is there is such line, False if not</returns>
        public Boolean IsAvaliablePlayer()
        {
            
            bool isAvaliablePlayer = false;            
            foreach (Player P in  Global.Game.Teams[this.playerTeamIndex].TeamPlayers)
            {
                Random rand = new Random();
                if (P != this)
                {
                    if (this.myHalfCort == Global.PartOfcourt.Left && P.PositionOnCourt.Y > 18)
                    {
                        if (hasClearPathBetweenPoints(PositionOnCourt, P.PositionOnCourt))
                        {
                            double dist = Math.Sqrt(Math.Pow(PositionOnCourt.X - P.PositionOnCourt.X, 2) + Math.Pow(PositionOnCourt.Y - P.PositionOnCourt.Y, 2));
                            if (dist >= (double)rand.Next(2, 6) && dist <= (double)rand.Next(7, 10))
                            {
                                isAvaliablePlayer = true;
                                break;
                            }
                        }
                    }
                    else if (this.myHalfCort == Global.PartOfcourt.Right && P.PositionOnCourt.Y < 18)
                    {
                        if (hasClearPathBetweenPoints(PositionOnCourt, P.PositionOnCourt))
                        {
                            double dist = Math.Sqrt(Math.Pow(PositionOnCourt.X - P.PositionOnCourt.X, 2) + Math.Pow(PositionOnCourt.Y - P.PositionOnCourt.Y, 2));
                            if (dist >= (double)rand.Next(2, 6) && dist <= (double)rand.Next(7, 10))
                            {
                                isAvaliablePlayer = true;
                                break;
                            }
                        }
                    }

                }
            }

            return isAvaliablePlayer;

        }

        /// <summary>
            /// Check if any player(in any team) has the ball
            /// </summary>
            /// <returns>True if a player has the ball </returns>
        public Boolean IsAnyoneHasTheBall()
            {
                Boolean ball = false;
                foreach (Team t in Global.Game.Teams)
                {
                    foreach (Player p in t.TeamPlayers)
                    {
                        if (p.HasBall)
                        {
                            ball = true;
                        }
                    }
                }

                return ball;
            }

        /// <summary>
          /// Checks if the player is in his half court
          /// </summary>
          /// <returns>return true if he is false if not</returns>
        public Boolean AmIinmyTeamHalfCourt()
          {
              if (this.PositionOnCourt.Y < Properties.Settings.Default.CourtCols / 2) // the player on left side  
              {
                  if (this.myHalfCort == Global.PartOfcourt.Left)// the player half court side is left             
                      return true;
                  else
                      return false;
              }
              else// the player on right side  
              {
                  if (this.myHalfCort == Global.PartOfcourt.Right)// the player half court side is right            
                      return true;
                  else
                      return false;
              }              
          }

        /// <summary>
        /// Checks if player stand on the 3 point line
        /// </summary>
        /// <returns>true or false</returns>
        public Boolean AmIin3PointLine()
        {
            Point rightbasket = new Point( Convert.ToInt32(Properties.Settings.Default.rightBasketInitSpread.Split(',')[0]),
                Convert.ToInt32(Properties.Settings.Default.rightBasketInitSpread.Split(',')[1]));
            Point leftbasket = new Point(Convert.ToInt32(Properties.Settings.Default.leftBasketInitSpread.Split(',')[0]),
                Convert.ToInt32(Properties.Settings.Default.leftBasketInitSpread.Split(',')[1]));
          
            // defining the points on the 3 point line
            Point[] Leftcourt3PointLine = { 
                    new Point(2,leftbasket.Y + 1), new Point(2,leftbasket.Y +2),new Point(2,leftbasket.Y +3),
                    new Point(2,leftbasket.Y +4), new Point(2,leftbasket.Y +5), new Point(2,leftbasket.Y +6),
                    new Point(3,leftbasket.Y +7), new Point(4,leftbasket.Y +8), new Point(5,leftbasket.Y +9),
                    new Point(6,leftbasket.Y +9),new Point(7,leftbasket.Y +9),new Point(8,leftbasket.Y +9),
                    new Point(9,leftbasket.Y +9),new Point(10,leftbasket.Y +9),new Point(11,leftbasket.Y +9),
                    new Point(12,leftbasket.Y +9),new Point(13,leftbasket.Y +9),new Point(14,leftbasket.Y +9),
                    new Point(15,leftbasket.Y +8),new Point(16,leftbasket.Y +7),new Point(17,leftbasket.Y +6),new Point(17,leftbasket.Y +5),
                    new Point(17,leftbasket.Y +4),new Point(17,leftbasket.Y +3), new Point(17,leftbasket.Y +2),new Point(17,leftbasket.Y +1) 
                                          };
            Point[] Rightcourt3PointLine = { 
                    new Point(2,rightbasket.Y - 1), new Point(2,rightbasket.Y -2),new Point(2,rightbasket.Y -3),new Point(2,rightbasket.Y -4),
                    new Point(2,rightbasket.Y -5), new Point(2,rightbasket.Y -6),new Point(3,rightbasket.Y -7), new Point(4,rightbasket.Y -8),
                    new Point(5,rightbasket.Y -9),new Point(6,rightbasket.Y -9),new Point(7,rightbasket.Y -9),new Point(8,rightbasket.Y -9),
                    new Point(9,rightbasket.Y -9),new Point(10,rightbasket.Y -9),new Point(11,rightbasket.Y -9),new Point(12,rightbasket.Y -9),
                    new Point(13,rightbasket.Y -9),new Point(14,rightbasket.Y -9),new Point(15,rightbasket.Y -8),new Point(16,rightbasket.Y -7),
                    new Point(17,rightbasket.Y -6),new Point(17,rightbasket.Y -5),new Point(17,rightbasket.Y -4),new Point(17,rightbasket.Y -3),
                    new Point(17,rightbasket.Y -2),new Point(17,rightbasket.Y -1) 
                                          }; 
            Team myteam = Global.Game.Teams[0];
            // determents which in team the player is
            if (AmIinTeam(Global.Game.Teams[0]))
            {
                myteam = Global.Game.Teams[0];
            }
            else
            {
                myteam = Global.Game.Teams[1];
            }

            if (myteam.TargetBasket.PositionOnCourt == leftbasket)
            {
                foreach(Point p in Leftcourt3PointLine)
                {
                    if (p == this.PositionOnCourt)
                        return true;
                    else
                        return false;
                }
            } 
            else
            {
                foreach (Point p in Rightcourt3PointLine)
                {
                    if (p == this.PositionOnCourt)
                        return true;
                    else
                        return false;
                }
            }

            // function should not get to this point, but if it does then return false
            return false;
        }

        /// <summary>
        /// Check if this player is the ball destination
        /// </summary>
        /// <returns>true if he is, otherwize false</returns>
        public Boolean IsBallThrownToMe()
        {
            
            bool isThrownToMe=false;
            Point destination=Global.Game.ConvertPositionFromPix2Mat(Global.Game.Ball.DestinationOnCourtPix);
            if(destination!=null&&destination!=Point.Empty)
            {
                if (destination == this.PositionOnCourt)
                    isThrownToMe = true;
                else
                {
                    Point tempDestination = new Point();
                    //Around destination.
                    for (int i = 0; i < 8; i++)
                    {
                        tempDestination.X = destination.X + direction[i, 0];
                        tempDestination.Y = destination.Y + direction[i, 1];
                        if (tempDestination == this.PositionOnCourt)
                        {
                            isThrownToMe = true;
                            break;
                        }
                    }
                }
            }
             return isThrownToMe;
        }

        /// <summary>
        /// Checks if there is a stright line between this player and the ball
        /// </summary>
        /// <returns>true if he is, otherwize false</returns>
        public Boolean IsStrightLineToBall()
        {
            return hasClearPathBetweenPoints(PositionOnCourt, Global.Game.Ball.PositionOnCourt);
        }
        

        #endregion

        #region Offence Player Actions
     
        /// <summary>
        /// Change the target of a ball to target basket.
        /// </summary>
        private void ThrowToBusket()
        {
            trace(this.PlayerName + " function - ThrowToBusket");
            Global.Game.Ball.DestinationOnCourtPix = Global.Game.ConvertPositionFromMat2Pix(Global.Game.Teams[this.playerTeamIndex].TargetBasket.PositionOnCourt);
            this.HasBall = false;
        }
     
        //test need to be change!!!
        private void DeliveryBall()
        {
          
            Point toPlayerPosition = Point.Empty;
            foreach (Player P in Global.Game.Teams[this.playerTeamIndex].TeamPlayers)
            {
                if (P != this)
                {
                    if (hasClearPathBetweenPoints(PositionOnCourt, P.PositionOnCourt))
                    {
                        toPlayerPosition = P.PositionOnCourt;
                    }
                }
                if (toPlayerPosition != Point.Empty)
                    break;
            }
            if (toPlayerPosition != Point.Empty)
            {
                Global.Game.Ball.DestinationOnCourtPix = Global.Game.ConvertPositionFromMat2Pix(toPlayerPosition);
                this.HasBall = false;
                trace(this.PlayerName + " function - DeliveryBall");
            }

        }

        /// <summary>
        /// Player move forward.
        /// </summary>
        private void MoveToBasket()
        {

            Point destinationPoint = Global.Game.Teams[this.playerTeamIndex].TargetBasket.PositionOnCourt;             
            this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);            
            this.Move();
            trace(this.PlayerName + " function - MoveToBasket");
        }

        /// <summary>
        /// Player move to half of the second group.
        /// </summary>
        private void GoToSecondHalf()
        {
            if (this.myHalfCort == Global.PartOfcourt.Left)
            {
                Point destinationPoint = Global.Game.FindPointInAreaByMeaning(Global.LocationMeaningOnCourt.NoMeaning, Global.PartOfcourt.Right,this.role,this.PositionOnCourt,-1);
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            }
            else if (this.myHalfCort == Global.PartOfcourt.Right)
            {
                Point destinationPoint = Global.Game.FindPointInAreaByMeaning(Global.LocationMeaningOnCourt.NoMeaning, Global.PartOfcourt.Left, this.role, this.PositionOnCourt,-1);
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            }
            this.Move();
            trace(this.PlayerName + " function - GoToSecondHalf");
        }

        /// <summary>
        /// Player move to three line of the second group.
        /// </summary>
        private void GoToThreeLine()
        {
            if (this.myHalfCort == Global.PartOfcourt.Left)
            {
                Point destinationPoint = Global.Game.FindPointInAreaByMeaning(Global.LocationMeaningOnCourt.ThreePoints, Global.PartOfcourt.Right, this.role, this.PositionOnCourt, -1);
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            }
            else if (this.myHalfCort == Global.PartOfcourt.Right)
            {
                Point destinationPoint = Global.Game.FindPointInAreaByMeaning(Global.LocationMeaningOnCourt.ThreePoints, Global.PartOfcourt.Left, this.role, this.PositionOnCourt, -1);
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            }
            this.Move();
            trace(this.PlayerName + " function - GoToThreeLine");
        }

        /// <summary>
        /// Player do not move.
        /// </summary>
        private void Stand()
        {
            if (this.DestinationPath != null)
            {
                this.DestinationPath.Clear();                
                trace(this.PlayerName + " function - Stand");
            }
        }

        /// <summary>
        /// Player move in the random way in the radius 3 meter.
        /// </summary>
        private void MoveByRadius3()
        {
            int radius =3;
            Point destinationPoint = Global.Game.FindPointInAreaByMeaning(Global.LocationMeaningOnCourt.NoMeaning, Global.PartOfcourt.All, this.role, this.PositionOnCourt, radius);
            this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            this.Move();
            trace(this.PlayerName + " function - MoveByRadius3");
        }

        /// <summary>
        /// Player move to ball.
        /// </summary>
        private void GoToBall()        
        {
            Point destinationPoint = Global.Game.ConvertPositionFromPix2Mat(Global.Game.Ball.DestinationOnCourtPix);
            if(destinationPoint!=null)
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
            this.Move();
            trace(this.PlayerName + " function - GoToBall");
        }

        #endregion

        #region Defence Player Actions
            
            /// <summary>
            /// Move player to initial guarding point
            /// </summary>
            private void GoToGuardInitialPosition()
            {
                if ( this.PositionOnCourt != InitialGuardingPoint)
                {
                    Point destinationPoint = InitialGuardingPoint;
                    this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
                    this.Move();
                    trace(this.PlayerName + " function - Move to initial guarding point");
                }
            }

            /// <summary>
            /// Move player to guarding point
            /// </summary>
            private void GotoGuardingPoint()
            {
                Point destinationPoint = GuardingPoint();
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
                this.Move();
                trace(this.PlayerName + " function - Move to guarding point");
            }

            /// <summary>
            /// Updates that the player I am guarding on has the ball
            /// </summary>
            private void UpdateGuardingPlayerWithBall()
            {
                GuardHadBall = true;
            }
            
            /// <summary>
            /// Moves towards the ball and Updates that the player I am guarding on doesn't have the ball
            /// </summary>
            private void GoToBallAndUpdate()
            {
                Point destinationPoint = Global.Game.Ball.PositionOnCourt;
                this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
                this.Move();
                trace(this.PlayerName + " function - Move towards the ball");
                GuardHadBall = false;

            }

            /// <summary>
            /// Idle function
            /// </summary>
            private void stand()
            {

            }

            /// <summary>
            /// This function should be call from outside (from Game), when the other hit the basket 
            /// (attach is done) and the other team should take the ball and start an attack
            /// </summary>
            public void GoAndTakeBallFromBasket()
            {
                Point destinationPoint = Global.Game.Ball.PositionOnCourt;
                if (this.PositionOnCourt == Global.Game.Ball.PositionOnCourt)
                {
                    this.HasBall = true;
                    if (this.AmIinTeam(Global.Game.Teams[0]))
                    {
                        Global.Game.Teams[0].TeamStatus = Global.TeamStatus.Offence;
                        Global.Game.Teams[1].TeamStatus = Global.TeamStatus.Defence;
                    }
                    else
                    {
                        Global.Game.Teams[1].TeamStatus = Global.TeamStatus.Offence;
                        Global.Game.Teams[0].TeamStatus = Global.TeamStatus.Defence;
                    }
                    TakeBallFromBasket = false;
                }
                else if (this.PositionOnCourt == new Point(Global.Game.Ball.PositionOnCourt.X,Global.Game.Ball.PositionOnCourt.Y-1)
                    || this.PositionOnCourt == new Point(Global.Game.Ball.PositionOnCourt.X, Global.Game.Ball.PositionOnCourt.Y+1))
                {
                    if (Global.Game.Ball.PositionOnCourt.Y > 18)
                        Global.Game.Ball.DestinationOnCourtPix = Global.Game.ConvertPositionFromMat2Pix(new Point(Global.Game.Ball.PositionOnCourt.X, Global.Game.Ball.PositionOnCourt.Y - 1));
                    else
                        Global.Game.Ball.DestinationOnCourtPix = Global.Game.ConvertPositionFromMat2Pix(new Point(Global.Game.Ball.PositionOnCourt.X, Global.Game.Ball.PositionOnCourt.Y + 1));
                }
                else
                {
                    TakeBallFromBasket = true;
                    //this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, (destinationPoint == Point.Empty) ? this.PositionOnCourt : destinationPoint);
                    if (Global.Game.Ball.PositionOnCourt.Y > 18)
                        this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, new Point(Global.Game.Ball.PositionOnCourt.X, Global.Game.Ball.PositionOnCourt.Y - 1));
                    else
                        this.DestinationPath = Global.Game.FindPath(this.PositionOnCourt, new Point(Global.Game.Ball.PositionOnCourt.X, Global.Game.Ball.PositionOnCourt.Y + 1));
                    this.Move();
                    trace(this.PlayerName + " function - Go to take ball from basket");
                }
            }

        #endregion Defence Player Actions

        #region Defance Player Questions

            /// <summary>
            /// Checks if the player I am guarding on is in my half court side
            /// </summary>
            /// <returns>true he is, otherwise false</returns>

            public Boolean IsPlayerGuardedInMyhalfCourt()
            {
                 return (!GuardOnPlayer.AmIinmyTeamHalfCourt());
            }
            
            /// <summary>
            /// Checks if the player is in his guarding point
            /// </summary>
            /// <returns>true he is, otherwise false</returns>
            public Boolean AmIinGuardingPoint()
            {
                return (this.PositionOnCourt == GuardingPoint());
            }
            
            /// <summary>
            /// Check if the player I am guarding on has the ball
            /// </summary>
            /// <returns>true he is, otherwise false</returns>
            public Boolean IsGuardingPlayerWithBall()
            {
                return this.GuardOnPlayer.HasBall;
            }


            /// <summary>
            /// Check if the player I am guarding on had the ball before
            /// </summary>
            /// <returns>true he is, otherwise false</returns>
            public Boolean DidGuadrdingPlayerHadBall()
            {
                return GuardHadBall;
            }

            /// <summary>
            /// Check if I am close to the guard and the ball
            /// </summary>
            /// <returns>true he is, otherwise false</returns>
            public Boolean AmIcloseToBallAndGuard()
            {
                int radiusfromball = 3;
                int radiusfromguard = 4;
                int rangefromplayer, rangefromball;

                rangefromplayer =
                  (int)Math.Sqrt(
                  Math.Abs(PositionOnCourt.X - this.GuardOnPlayer.PositionOnCourt.X) *
                       Math.Abs(PositionOnCourt.X - this.GuardOnPlayer.PositionOnCourt.X)
                  +
                  (
                  Math.Abs(PositionOnCourt.Y - this.GuardOnPlayer.PositionOnCourt.Y) *
                       Math.Abs(PositionOnCourt.Y - this.GuardOnPlayer.PositionOnCourt.Y)
                  )
                  );

                rangefromball =
                    (int)Math.Sqrt(
                  Math.Abs(PositionOnCourt.X - Global.Game.Ball.PositionOnCourt.X) *
                       Math.Abs(PositionOnCourt.X - Global.Game.Ball.PositionOnCourt.X)
                  +
                  (
                  Math.Abs(PositionOnCourt.Y - Global.Game.Ball.PositionOnCourt.Y) *
                       Math.Abs(PositionOnCourt.Y - Global.Game.Ball.PositionOnCourt.Y)
                  )
                  );

                return (rangefromball <= radiusfromball && rangefromplayer <= radiusfromguard);

            }

            /// <summary>
            /// Check if the ball was thrown to the player I am guarding on
            /// </summary>
            /// <returns>true he is, otherwise false</returns>
            public Boolean IsBallOnHisWayToGruardingPlayer()
            {
                return (Global.Game.ConvertPositionFromPix2Mat(Global.Game.Ball.DestinationOnCourtPix) == this.GuardOnPlayer.PositionOnCourt);
            }
            
        #endregion

        #region Usefull Methods
        /// <summary>
        /// The function checks if there is a clear path between 2 points.
        /// </summary>
        /// <param name="source">source point on matrix</param>
        /// <param name="destination">destination point on matrix</param>
        /// <returns>true or false</returns>
        private bool hasClearPathBetweenPoints(Point source, Point destination)
        {
            List<PointF> XAxisIntersection = new List<PointF>();
            List<PointF> YAxisIntersection = new List<PointF>();
            PointConverter p = new PointConverter();
            int Ymat, Xmat;
            float Y, X, m;
            bool isMovingForward,isMovingUp,isPathEmpty = true;
            // Calculates the M of the line
            m = ((float)(destination.Y - source.Y)) / ((float)(destination.X - source.X));
            // Calculates the intersection points between straight line equation to matrix columns
            if (source.X <= destination.X)
            {
                isMovingForward = true;
                Xmat = source.X;
            }
            else
            {
                isMovingForward = false;
                Xmat = source.X;
            }
            for (; (isMovingForward) ? Xmat < destination.X : Xmat > destination.X;)
            {
                Y = m * (Xmat - source.X) + source.Y;
                XAxisIntersection.Add(new PointF(Xmat, Y));
                if (isMovingForward)
                    Xmat += 1;
                else
                    Xmat -= 1;
            }
            // Calculates the intersection points between straight line equation to matrix rows
            if (source.Y <= destination.Y)
            {
                Ymat = source.Y;
                isMovingUp = true;
            }
            else
            {
                Ymat = source.Y;
                isMovingUp = false;
            }
            for (; (isMovingUp) ? Ymat < destination.Y : Ymat > destination.Y;)
            {
                X = (Ymat - source.Y) / m + source.X;
                YAxisIntersection.Add(new PointF(X, Ymat));
                if (isMovingUp)
                    Ymat++;
                else
                    Ymat--;
            }
            for(int i=1;i < XAxisIntersection.Count;i++)
            {
                Point left = new Point(Convert.ToInt32(XAxisIntersection[i].X) - 1, Convert.ToInt32(Math.Floor(XAxisIntersection[i].Y)));
                Point right = new Point(Convert.ToInt32(XAxisIntersection[i].X), Convert.ToInt32(Math.Floor(XAxisIntersection[i].Y)));
                if (Math.Floor(XAxisIntersection[i].Y) == XAxisIntersection[i].Y)
                {
                    Point upLeft = new Point(Convert.ToInt32(XAxisIntersection[i].X) - 1, Convert.ToInt32(XAxisIntersection[i].Y) - 1);
                    Point upRight = new Point(Convert.ToInt32(XAxisIntersection[i].X), Convert.ToInt32(XAxisIntersection[i].Y) - 1);
                    if (upLeft != destination && upLeft != source && upRight != destination && upRight != source)
                        if (!(Global.Game.isCourtLocationEmpty(upLeft) && Global.Game.isCourtLocationEmpty(upRight)))
                        {
                            isPathEmpty = false;
                            break;
                        }
                }
                if (left != destination && left != source && right != destination && right != source)
                    if (!(Global.Game.isCourtLocationEmpty(left) && Global.Game.isCourtLocationEmpty(right)))
                    {
                        isPathEmpty = false;
                        break;
                    }
                    
            }
            if(isPathEmpty)
                for (int i = 1; i < YAxisIntersection.Count; i++)
                {
                    Point up = new Point(Convert.ToInt32(Math.Floor(YAxisIntersection[i].X)), Convert.ToInt32(YAxisIntersection[i].Y) - 1);
                    Point down = new Point(Convert.ToInt32(Math.Floor(YAxisIntersection[i].X)), Convert.ToInt32(YAxisIntersection[i].Y));
                    if (Math.Floor(YAxisIntersection[i].X) == YAxisIntersection[i].X)
                    {
                        Point upLeft = new Point(Convert.ToInt32(YAxisIntersection[i].X) - 1, Convert.ToInt32(YAxisIntersection[i].Y) - 1);
                        Point downLeft = new Point(Convert.ToInt32(YAxisIntersection[i].X) - 1, Convert.ToInt32(YAxisIntersection[i].Y));
                        if (downLeft != destination && downLeft != source && upLeft != destination && upLeft != source)
                            if (!(Global.Game.isCourtLocationEmpty(downLeft) && Global.Game.isCourtLocationEmpty(upLeft)))
                            {
                                isPathEmpty = false;
                                break;
                            }
                    }
                    if (up != destination && up != source && down != destination && down != source)
                        if (!(Global.Game.isCourtLocationEmpty(up) && Global.Game.isCourtLocationEmpty(down)))
                        {
                            isPathEmpty = false;
                            break;
                        }
                }
            
            return isPathEmpty;

        }

        /// <summary>
        /// Checks if a player belongs to specific team
        /// </summary>
        /// <param name="team">The check team</param>
        /// <returns>True if the player belongs, False if not</returns>
        public Boolean AmIinTeam(Team team)
        {
            foreach (Player P in team.TeamPlayers)
            {
                if (P == this)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Function calculates the guarding point
        /// </summary>
        /// <returns>Guarding point position</returns>
        private Point GuardingPoint()
        {
            Point p = new Point();
            int token;
            if (this.GuardOnPlayer.PositionOnCourt.Y > 11 || this.GuardOnPlayer.PositionOnCourt.Y < 23)
            {
                token = 2; 
            }
            else if (this.GuardOnPlayer.PositionOnCourt.X > 5 && this.GuardOnPlayer.PositionOnCourt.X < 13)
                {
                    token = 2;
                }
            else if (this.GuardOnPlayer.PositionOnCourt.Y > 6 || this.GuardOnPlayer.PositionOnCourt.Y < 28)
            {
                token = 1;
            }
            else
            {
                token = 0;
            }

            switch (token)
            {
                case 0:
                    {
                        if (this.GuardOnPlayer.PositionOnCourt.X < 6)
                        {
                            p.Y = this.GuardOnPlayer.PositionOnCourt.Y;
                            p.X = this.GuardOnPlayer.PositionOnCourt.X + 2;
                            break;
                        } 
                        else
                        {
                            p.Y = this.GuardOnPlayer.PositionOnCourt.Y;
                            p.X = this.GuardOnPlayer.PositionOnCourt.X - 2;
                            break;
                        }
                    }
            	        
                case 1 : 
                    {
                        if (this.GuardOnPlayer.PositionOnCourt.Y < 18 )
                        {
                            if (this.GuardOnPlayer.PositionOnCourt.X < 6)
                            {
                                p.Y = this.GuardOnPlayer.PositionOnCourt.Y - 2;
                                p.X = this.GuardOnPlayer.PositionOnCourt.X + 2;
                                break;
                            }
                            else
                            {
                                p.Y = this.GuardOnPlayer.PositionOnCourt.Y + 2;
                                p.X = this.GuardOnPlayer.PositionOnCourt.X - 2;
                                break;
                            }
                        }
                        else
                        {
                            if (this.GuardOnPlayer.PositionOnCourt.X < 6)
                            {
                                p.Y = this.GuardOnPlayer.PositionOnCourt.Y + 2;
                                p.X = this.GuardOnPlayer.PositionOnCourt.X + 2;
                                break;
                            }
                            else
                            {
                                p.Y = this.GuardOnPlayer.PositionOnCourt.Y - 2;
                                p.X = this.GuardOnPlayer.PositionOnCourt.X - 2;
                                break;
                            }
                        }
                    }

                case 2:
                    {
                        if (this.GuardOnPlayer.PositionOnCourt.Y < 18 )
                        {
                            p.X = this.GuardOnPlayer.PositionOnCourt.X;
                            p.Y = this.GuardOnPlayer.PositionOnCourt.Y - 2;
                            break;
                        }
                        else
                        {
                            p.X = this.GuardOnPlayer.PositionOnCourt.X;
                            p.Y = this.GuardOnPlayer.PositionOnCourt.Y + 2;
                            break;
                        }
                    }
            }
            return p;
        }

        #endregion

        #region Desition Tree
        public void MakeDecision()
        {
            if (TakeBallFromBasket)
            {
                GoAndTakeBallFromBasket();
            }
            else
            {
                if (Global.Game.Teams[this.playerTeamIndex].TeamStatus == Global.TeamStatus.Offence)
                    this.offenceDecitionTree.ScanTree();
                else  //defense
                    this.defenceDecitionTree.ScanTree();
            }

        }
        private void BuildOffenceDecisionTree()
        {
            #region Attribute  Question

            DecTrees.Question Q_DoIhaveTheBall = new Question(DoIhaveTheBall);
            DecTrees.Question Q_AmIinShootingRange = new Question(AmIinShootingRange);
            DecTrees.Question Q_IsStrightLineToBasket = new Question(IsStrightLineToBasket);
            DecTrees.Question Q_IsAnyoneHasTheBall = new Question(IsAnyoneHasTheBall);
            DecTrees.Question Q_AmIinmyTeamHalfCourt = new Question(AmIinmyTeamHalfCourt);
            DecTrees.Question Q_AmIin3PointLine = new Question(AmIin3PointLine);
            DecTrees.Question Q_IsBallThrownToMe = new Question(IsBallThrownToMe);
            DecTrees.Question Q_IsStrightLineToBall = new Question(IsStrightLineToBall);
            DecTrees.Question Q_IsAvaliablePlayer = new Question(IsAvaliablePlayer);
            
            #endregion Attribute  Question
            
            #region Attribute  Action

            DecTrees.Action A_ThrowToBusket = new DecTrees.Action(ThrowToBusket);
            DecTrees.Action A_DeliveryBall = new DecTrees.Action(DeliveryBall);
            DecTrees.Action A_MoveToBasket = new DecTrees.Action(MoveToBasket);
            DecTrees.Action A_GoToSecondHalf = new DecTrees.Action(GoToSecondHalf);
            DecTrees.Action A_GoToThreeLine = new DecTrees.Action(GoToThreeLine);
            DecTrees.Action A_Stand = new DecTrees.Action(Stand);
            DecTrees.Action A_MoveByRadius3 = new DecTrees.Action(MoveByRadius3);
            DecTrees.Action A_GoToBall = new DecTrees.Action(GoToBall);

            #endregion Attribute  Action

            #region Build Tree
            TreeNode root = new TreeNode(new DecTrees.Attribute("DoIhaveTheBall", Q_DoIhaveTheBall));
            TreeNode leftNode;
            TreeNode rightNode;
            TreeNode parent;
            TreeNode tmpNode;      
            //Build left root.
            leftNode = new TreeNode(new DecTrees.Attribute("GoToThreeLine", A_GoToThreeLine));
            rightNode=new TreeNode(new DecTrees.Attribute("MoveByRadius3",A_MoveByRadius3));      
            parent = new TreeNode(new DecTrees.Attribute("AmIin3PointLine", Q_AmIin3PointLine));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode = parent;

            parent = new TreeNode(new DecTrees.Attribute("AmIinmyTeamHalfCourt",Q_AmIinmyTeamHalfCourt));           
            rightNode = new TreeNode(new DecTrees.Attribute("GoToSecondHalf",A_GoToSecondHalf));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            tmpNode = parent;                      


            leftNode=new TreeNode(new DecTrees.Attribute("Stand",A_Stand));
            rightNode=new TreeNode(new DecTrees.Attribute("GoToBall",A_GoToBall));
            parent=new TreeNode(new DecTrees.Attribute("IsStrightLineToBall",Q_IsStrightLineToBall));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode=tmpNode;
            rightNode=parent;
            parent=new TreeNode(new DecTrees.Attribute("IsBallThrownToMe",Q_IsBallThrownToMe));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            tmpNode = parent;                     
                      
            leftNode=new TreeNode(new DecTrees.Attribute("GoToThreeLine",A_GoToThreeLine));
            rightNode = new TreeNode(new DecTrees.Attribute("MoveByRadius3", A_MoveByRadius3));      
            parent=new TreeNode(new DecTrees.Attribute("AmIin3PointLine",Q_AmIin3PointLine));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode = parent;
            rightNode = new TreeNode(new DecTrees.Attribute("A_GoToSecondHalf", A_GoToSecondHalf));
            parent=new TreeNode(new DecTrees.Attribute("AmIinmyTeamHalfCourt",Q_AmIinmyTeamHalfCourt));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode=tmpNode;
            rightNode =parent;

            parent = new TreeNode(new DecTrees.Attribute("IsAnyoneHasTheBall", Q_IsAnyoneHasTheBall));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);            
            //add left root.
            root.AddLeftTreeNode(parent);
            //Build right root.

            leftNode = new TreeNode(new DecTrees.Attribute("MoveToBasket", A_MoveToBasket));
            rightNode=new TreeNode(new DecTrees.Attribute("DeliveryBall",A_DeliveryBall));
            parent=new TreeNode(new DecTrees.Attribute("IsAvaliablePlayer",Q_IsAvaliablePlayer));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode=parent;
            rightNode=new TreeNode(new DecTrees.Attribute("MoveToBasket",A_MoveToBasket));
            parent=new TreeNode(new DecTrees.Attribute("IsStrightLineToBasket",Q_IsStrightLineToBasket));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            tmpNode=parent;

            leftNode=new TreeNode(new DecTrees.Attribute("MoveByRadius3",A_MoveByRadius3));
            rightNode=new TreeNode( new DecTrees.Attribute("DeliveryBall",A_DeliveryBall));
            parent=new TreeNode(new DecTrees.Attribute("IsAvaliablePlayer",Q_IsAvaliablePlayer));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode=parent;
            rightNode=new TreeNode(new DecTrees.Attribute("ThrowToBusket",A_ThrowToBusket));
            parent=new TreeNode(new DecTrees.Attribute("IsStrightLineToBasket",Q_IsStrightLineToBasket));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            leftNode=tmpNode;
            rightNode=parent;
            parent=new TreeNode(new DecTrees.Attribute("AmIinShootingRange",Q_AmIinShootingRange));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            //add right root.
            root.AddRightTreeNode(parent);
            offenceDecitionTree = new decitionTree(root);
            #endregion Build Tree 
           
        }

        private void BuildDefenceDecisionTree()
        {
            #region Attribute  Question

            DecTrees.Question Q_AmIinmyTeamHalfCourt = new Question(AmIinmyTeamHalfCourt);
            DecTrees.Question Q_IsGuardedPlayerInMyHalfCourt = new Question(IsPlayerGuardedInMyhalfCourt);
            DecTrees.Question Q_AmIinGuardingPoint = new Question(AmIinGuardingPoint);
            DecTrees.Question Q_DoGuardedPlayerhaveTheBall = new Question(IsGuardingPlayerWithBall);
            DecTrees.Question Q_DidGuardedPlayerHadTheBall = new Question(DidGuadrdingPlayerHadBall);
            DecTrees.Question Q_AmICloseToTheBall = new Question(AmIcloseToBallAndGuard);
            DecTrees.Question Q_IsBallInWayToGuardedPlayer = new Question(IsBallOnHisWayToGruardingPlayer);
            
            #endregion Attribute  Question

            #region Attribute  Action

            DecTrees.Action A_Stand = new DecTrees.Action(Stand);
            DecTrees.Action A_GoToInitialPoint = new DecTrees.Action(GoToGuardInitialPosition);
            DecTrees.Action A_GoToGuardingPoint = new DecTrees.Action(GotoGuardingPoint);
            DecTrees.Action A_UpdateGuardedPlayerWithBall = new DecTrees.Action(UpdateGuardingPlayerWithBall);
            DecTrees.Action A_GoToBallAndUpdate = new DecTrees.Action(GoToBallAndUpdate);
            

            #endregion Attribute  Action

            #region Build Tree
      
            TreeNode root = new TreeNode(new DecTrees.Attribute("AmIinmyTeamHalfCourt", Q_AmIinmyTeamHalfCourt));
            TreeNode leftNode;
            TreeNode rightNode;
            TreeNode parent;
            TreeNode tmpNode;

            parent = new TreeNode(new DecTrees.Attribute("IsTheBallOnHisWayToGuardedPlayer", Q_IsBallInWayToGuardedPlayer));
            leftNode = new TreeNode(new DecTrees.Attribute("stand", A_Stand));
            rightNode = new TreeNode(new DecTrees.Attribute("GoToBallAndUpdate", A_GoToBallAndUpdate));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);
            tmpNode = parent;

            parent = new TreeNode(new DecTrees.Attribute("DidGuardedPlayerHadTheBall", Q_DidGuardedPlayerHadTheBall));
            parent.AddLeftTreeNode(tmpNode);
            tmpNode = parent;

            parent = new TreeNode(new DecTrees.Attribute("AmICloseToBall",Q_AmICloseToTheBall));
            leftNode = new TreeNode(new DecTrees.Attribute("Stand",A_Stand));
            rightNode = new TreeNode(new DecTrees.Attribute("GoToBallAndUpdate",A_GoToBallAndUpdate));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);

            tmpNode.AddRightTreeNode(parent);

            leftNode = tmpNode;
            parent = new TreeNode(new DecTrees.Attribute("DoGuardedPlayerhaveTheBall", Q_DoGuardedPlayerhaveTheBall));
            rightNode = new TreeNode(new DecTrees.Attribute("UpdateGuardedPlayerWithBall", A_UpdateGuardedPlayerWithBall));
            parent.AddRightTreeNode(rightNode);
            parent.AddLeftTreeNode(leftNode);

            tmpNode = parent;
            rightNode = tmpNode;
            parent = new TreeNode(new DecTrees.Attribute("AmIinGuardingPoint", Q_AmIinGuardingPoint));
            leftNode = new TreeNode(new DecTrees.Attribute("GoToGuardingPoint", A_GoToGuardingPoint));
            parent.AddLeftTreeNode(leftNode);
            parent.AddRightTreeNode(rightNode);

            tmpNode = parent;
            rightNode = tmpNode;
            parent = new TreeNode(new DecTrees.Attribute("IsGuardedPlayerInMyHalfCourt", Q_IsGuardedPlayerInMyHalfCourt));
            leftNode = new TreeNode(new DecTrees.Attribute("Stand", A_Stand));
            parent.AddRightTreeNode(rightNode);
            parent.AddLeftTreeNode(leftNode);

            rightNode = parent;
            leftNode = new TreeNode(new DecTrees.Attribute("GoToInitialPoint", A_GoToInitialPoint));
            root.AddRightTreeNode(rightNode);
            root.AddLeftTreeNode(leftNode);

            defenceDecitionTree = new decitionTree(root);
            #endregion Build Tree

        }
   
        #endregion
        #endregion
    }
}
